<template>
  <div class="containers">
    <h1>自定义Bpmn流程面板</h1>
    <div class="canvas" ref="canvas"></div>
    <div id="js-properties-panel" class="panel"></div>
  </div>
</template>

<script>
import propertiesPanelModule from 'bpmn-js-properties-panel'
import propertiesProviderModule from '../properties-panel-extension/provider/authority'
// import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
 import authorityModdleDescriptor from '../properties-panel-extension/descriptors/authority'
import customTranslate from '@/utils/customTranslate'
import { newDiagram } from './newDiagram'
import CustomModeler from '@/customModeler'
export default {
  props: {
    xmlUrl: {
      type: String,
      default: '',
    },
  },
  components: {},
  created() {},
  mounted() {
    this.init()
  },
  data() {
    return {
      bpmnModeler: null,
      container: null,
      canvas: null,
      defaultXmlStr: newDiagram,
    }
  },
  methods: {
    async init() {
      this.$nextTick(() => {
        this.initBpmn()
      })
    },
    initBpmn() {
      const canvas = this.$refs.canvas
      const customTranslateModule = {
          translate:['value', customTranslate]
        }
      this.bpmnModeler = new CustomModeler({
        container: canvas,
        //添加控制板
        propertiesPanel: {
          parent: '#js-properties-panel',
        },
        additionalModules: [
          propertiesPanelModule,
          propertiesProviderModule,
          customTranslateModule
        ],
        moddleExtensions:{
         // camunda:camundaModdleDescriptor,
          authority:authorityModdleDescriptor
        }
      })
      this.createNewDiagram()
    },
    createNewDiagram() {
      let bpmnXmlStr = ''
      if (this.xmlUrl === '') {
        bpmnXmlStr = this.defaultXmlStr
        this.transformCanvas(bpmnXmlStr)
      }
    },

    async transformCanvas(bpmnXmlStr) {
      // 将字符串转换成图显示出来
      try {
        const res = await this.bpmnModeler.importXML(bpmnXmlStr)
        console.log('--', res)
        this.success()
        // 让图能自适应屏幕
        var canvas = this.bpmnModeler.get('canvas')
        canvas.zoom('fit-viewport')
      } catch (error) {
        console.log(error)
      }
    },
    success() {
      this.addBpmnListener()
      this.addModelerListener()
      this.addEventBusListener()
    },
    // 添加绑定事件
    addBpmnListener() {
      const that = this
      // 获取a标签dom节点
      const downloadLink = this.$refs.saveDiagram
      const downloadSvgLink = this.$refs.saveSvg
      // 给图绑定事件，当图有发生改变就会触发这个事件
      this.bpmnModeler.on('commandStack.changed', function() {
        that.saveSVG(function(err, svg) {
          console.log('999',svg)
          that.setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg)
        })
        that.saveDiagram(function(err, xml) {
          that.setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml)
        })
      })
    },
    addModelerListener() {
      // 监听 modeler
      const bpmnjs = this.bpmnModeler
      const that = this
      // 'shape.removed', 'connect.end', 'connect.move'
      const events = ['shape.added', 'shape.move.end', 'shape.removed']
      events.forEach(function(event) {
        that.bpmnModeler.on(event, (e) => {
          var elementRegistry = bpmnjs.get('elementRegistry')
          var shape = e.element ? elementRegistry.get(e.element.id) : e.shape
          console.log(shape)
          if (event === 'shape.added') {
            console.log('新增了shape')
          } else if (event === 'shape.move.end') {
            console.log('移动了shape')
          } else if (event === 'shape.removed') {
            console.log('删除了shape')
          }
        })
      })
    },
    addEventBusListener() {
      // 监听 element
      let that = this
      const eventBus = this.bpmnModeler.get('eventBus')
      const eventTypes = ['element.click', 'element.changed']
      eventTypes.forEach(function(eventType) {
        eventBus.on(eventType, function(e) {
          if (!e || e.element.type == 'bpmn:Process') return
          if (eventType === 'element.changed') {
            that.elementChanged(e)
          } else if (eventType === 'element.click') {
            console.log('点击了element', e.element)
          }
        })
      })
    },
    isInvalid(param) {
      // 判断是否是无效的值
      return param === null || param === undefined || param === ''
    },
    isSequenceFlow(type) {
      // 判断是否是线
      return type === 'bpmn:SequenceFlow'
    },
    elementChanged(e) {
      var shape = this.getShape(e.element.id)
      console.log(shape)
      if (!shape) {
        // 若是shape为null则表示删除, 无论是shape还是connect删除都调用此处
        console.log('无效的shape')
        // 上面已经用 shape.removed 检测了shape的删除, 要是删除shape的话这里还会被再触发一次
        console.log('删除了shape和connect')
        return
      }
      if (!this.isInvalid(shape.type)) {
        if (this.isSequenceFlow(shape.type)) {
          console.log('改变了线')
        }
      }
    },
    getShape(id) {
      var elementRegistry = this.bpmnModeler.get('elementRegistry')
      return elementRegistry.get(id)
    },
    // 下载为SVG格式,done是个函数，调用的时候传入的
    saveSVG(done) {
      // 把传入的done再传给bpmn原型的saveSVG函数调用
      this.bpmnModeler.saveSVG(done)
    },
    // 下载为bpmn格式,done是个函数，调用的时候传入的
    saveDiagram(done) {
      // 把传入的done再传给bpmn原型的saveXML函数调用
      this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
        done(err, xml)
      })
    },
    // 当图发生改变的时候会调用这个函数，这个data就是图的xml
    setEncoded(link, name, data) {
      // 把xml转换为URI，下载要用到的
      // const encodedData = encodeURIComponent(data)
      // 下载图的具体操作,改变a的属性，className令a标签可点击，href令能下载，download是下载的文件的名字
      //   console.log(link, name, data)
      let xmlFile = new File([data], 'test.bpmn')
      console.log(xmlFile)
      if (data) {
        // link.className = 'active'
        // link.href = 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
        // link.download = name
      }
    },
  },
}
</script>

<style scoped>
.containers {
  background-color: #ffffff;
  width: 100%;
  height: calc(100vh - 52px);
}
.canvas {
  width: 100%;
  height: 100%;
  flex-grow: 1;
  background-image: linear-gradient(90deg,
      rgba(220, 220, 220, 0.5) 3%,
      transparent 0),
    linear-gradient(rgba(192, 192, 192, 0.5) 3%, transparent 0);
  background-size: 24px 24px;
  -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}
.panel {
  position: absolute;
  right: 0;
  top: 0;
  width: 300px;
}
.loading {
  font-size: 26px;
}
.containers {
  background-color: #ffffff;
  width: 100%;
  height: calc(100vh - 52px);
}
.canvas {
  width: 100%;
  height: 100%;
}
.panel {
  position: absolute;
  right: 0;
  top: 0;
  width: 300px;
}
</style>
